﻿using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Linq;
using TheSnakeGame.Engine;
using TheSnakeGame.Engine.GameObjects;


namespace Tests.TheSnakeGame.Engine
{
    [TestClass]
    public class WallFactoryTests
    {
        [TestMethod]
        [ExpectedException(typeof(ArgumentOutOfRangeException))]
        public void AssureWidthCannotBeLessThenThree()
        {
            var wallFactory = new WallFactory(1, 5);
        }

        [TestMethod]
        [ExpectedException(typeof(ArgumentOutOfRangeException))]
        public void AssureHeightCannotBeLessThenThree()
        {
            var wallFactory = new WallFactory(5, 1);
        }

        [TestMethod]
        public void GetFiveByFive_ShouldHave16WallObjects()
        {
            var wallFactory = new WallFactory(5, 5);
            var objectCollection = wallFactory.GetWalls();

            foreach (var wallObject in objectCollection)
            {
                Assert.IsTrue(wallObject is BarierObject, "WallFactory returned incorrent type of objects");
            }
            Assert.AreEqual(16, objectCollection.Count, "Incorrent number of wall object has been returned");
        }

        [TestMethod]
        public void GetFiveByFive_EnsureEachWallObjectHasCorrentCoordinates()
        {
            var coordinates = new[] 
            { 
                                      new { x = 1, y = 0 }, new { x = 2, y = 0 }, new { x = 3, y = 0 },                        // buttom row
                                      new { x = 1, y = 4 }, new { x = 2, y = 4 }, new { x = 3, y = 4 },                        // top row
                new { x = 0, y = 0 }, new { x = 0, y = 1 }, new { x = 0, y = 2 }, new { x = 0, y = 3 }, new { x = 0, y = 4 },  // left column
                new { x = 4, y = 0 }, new { x = 4, y = 1 }, new { x = 4, y = 2 }, new { x = 4, y = 3 }, new { x = 4, y = 4 },  // right  column

            };

            var wallFactory = new WallFactory(5, 5);
            var objectCollection = wallFactory.GetWalls();

            foreach (var coordPair in coordinates)
            {
                var corespondingWallObj = objectCollection.Cast<BarierObject>().FirstOrDefault(x => x.Position.X == coordPair.x && x.Position.Y == coordPair.y);
                Assert.IsNotNull(corespondingWallObj, "Object with requested coordinates was not found: {" + coordPair.x + ", " + coordPair.y + "}");
                objectCollection.Remove(corespondingWallObj);
            }

            Assert.AreEqual(0, objectCollection.Count, "Objects with coordinates that are not on the walls are available");
        }

        [TestMethod]
        public void GetThreeByThree_ShouldHave8WallObjects()
        {
            var wallFactory = new WallFactory(3, 3);
            var objectCollection = wallFactory.GetWalls();

            foreach (var wallObject in objectCollection)
            {
                Assert.IsTrue(wallObject is BarierObject, "WallFactory returned incorrent type of objects");
            }
            Assert.AreEqual(8, objectCollection.Count, "Incorrent number of wall object has been returned");
        }

        [TestMethod]
        public void GetThreeByThree_EnsureEachWallObjectHasCorrentCoordinates()
        {
            var coordinates = new[] 
            { 
                                      new { x = 1, y = 0 },                         // buttom row
                                      new { x = 1, y = 2 },                         // top row
                new { x = 0, y = 0 }, new { x = 0, y = 1 }, new { x = 0, y = 2 },   // left column
                new { x = 2, y = 0 }, new { x = 2, y = 1 }, new { x = 2, y = 2 },   // right  column

            };

            var wallFactory = new WallFactory(3, 3);
            var objectCollection = wallFactory.GetWalls();

            foreach (var coordPair in coordinates)
            {
                var corespondingWallObj = objectCollection.Cast<BarierObject>().FirstOrDefault(x => x.Position.X == coordPair.x && x.Position.Y == coordPair.y);
                Assert.IsNotNull(corespondingWallObj, "Object with requested coordinates was not found: {" + coordPair.x + ", " + coordPair.y + "}");
                objectCollection.Remove(corespondingWallObj);
            }

            Assert.AreEqual(0, objectCollection.Count, "Objects with coordinates that are not on the walls are available");
        }

        [TestMethod]
        public void GetThreeByFour_ShouldHave8WallObjects()
        {
            var wallFactory = new WallFactory(3, 4);
            var objectCollection = wallFactory.GetWalls();

            foreach (var wallObject in objectCollection)
            {
                Assert.IsTrue(wallObject is BarierObject, "WallFactory returned incorrent type of objects");
            }
            Assert.AreEqual(10, objectCollection.Count, "Incorrent number of wall object has been returned");
        }

        [TestMethod]
        public void GetFouryThree_ShouldHave8WallObjects()
        {
            var wallFactory = new WallFactory(4, 3);
            var objectCollection = wallFactory.GetWalls();

            foreach (var wallObject in objectCollection)
            {
                Assert.IsTrue(wallObject is BarierObject, "WallFactory returned incorrent type of objects");
            }
            Assert.AreEqual(10, objectCollection.Count, "Incorrent number of wall object has been returned");
        }

        [TestMethod]
        public void GetThreeByFour_EnsureEachWallObjectHasCorrentCoordinates()
        {
            var coordinates = new[] 
            { 
                                      new { x = 1, y = 0 }, new { x = 2, y = 0 },   // buttom row
                                      new { x = 1, y = 2 }, new { x = 2, y = 2 },   // top row
                new { x = 0, y = 0 }, new { x = 0, y = 1 }, new { x = 0, y = 2 },   // left column
                new { x = 3, y = 0 }, new { x = 3, y = 1 }, new { x = 3, y = 2 },   // right  column

            };

            var wallFactory = new WallFactory(4, 3);
            var objectCollection = wallFactory.GetWalls();

            foreach (var coordPair in coordinates)
            {
                var corespondingWallObj = objectCollection.Cast<BarierObject>().FirstOrDefault(x => x.Position.X == coordPair.x && x.Position.Y == coordPair.y);
                Assert.IsNotNull(corespondingWallObj, "Object with requested coordinates was not found: {" + coordPair.x + ", " + coordPair.y + "}");
                objectCollection.Remove(corespondingWallObj);
            }

            Assert.AreEqual(0, objectCollection.Count, "Objects with coordinates that are not on the walls are available");
        }
    }
}
